<template>
  <div ref="pipelineConfigRef" class="pipeline-config-container">
    <EmptyPipeline
      v-if="computedTasks.length == 0"
      text="暂无流程"
      btn-text="新建任务"
      @on-click="addSerialTask([], 0)"
      :is-view="isView"
    />
    <div v-else class="pipeline-config">
      <template v-for="(tasks, groupIndex) in computedTasks" :key="groupIndex">
        <div class="serial-task-add" v-if="groupIndex > 0 && groupIndex < computedTasks.length && !isView">
          <!-- 添加串行任务，非最后一个 -->
          <a-tooltip title="新建任务">
            <PlusCircleFilled
              class="add-icon"
              @click="addSerialTask(computedTasks[groupIndex - 1] || [], computedTasks.length)"
            />
          </a-tooltip>
        </div>
        <div class="task-group">
          <template v-for="(item, index) in orderBy(tasks || [], (t: Pipeline.Task) => t.sortIndex)" :key="item.uuid">
            <div class="task-item-container" :class="{ 'linked-item': index > 0 }">
              <div class="w-24"></div>
              <div
                class="task-item"
                :class="{ 'validate-error-border': item.isValidateError }"
                @click="openTaskEdit(item)"
              >
                {{ item.name }}
                <info-circle-filled v-if="item.isValidateError" class="validate-error-icon" />
              </div>
              <div class="w-24"></div>
            </div>
            <div class="parallel-wiring" v-if="index < (tasks || []).length - 1">
              <!-- 添加并行任务，非最后一个 -->
              <a-tooltip title="新建任务">
                <PlusCircleFilled
                  class="add-icon"
                  :style="{
                    position: 'absolute',
                    top: '12px',
                    left: '-8px',
                    cursor: 'pointer',
                  }"
                  @click="addParallelTask(item, (tasks || []).length)"
                  v-show="!isView"
                />
              </a-tooltip>
            </div>
            <div class="task-item-container linked" v-if="index == (tasks || []).length - 1 && !isView">
              <div
                class="task-item task-item-add task-item-add-hover"
                @click="addParallelTask(item, (tasks || []).length)"
              >
                <!-- 添加并行任务 -->
                <PlusCircleFilled class="add-icon" />
                并行任务
              </div>
            </div>
          </template>
        </div>
      </template>
      <div
        class="task-item task-item-add serial-task-add-last"
        @click="addSerialTask(computedTasks[computedTasks.length - 1] || [], computedTasks.length)"
        v-if="!isView"
      >
        <!-- 添加串行任务，最后一个 -->
        <PlusCircleFilled class="add-icon" />
        串行任务
      </div>
    </div>
  </div>
  <TaskAddModal ref="taskAddModalRef" @handle-add-task="handleAddTask" :data="taskDefList" />
  <TaskEditModal ref="taskEditModalRef" @delete="deleteSerialTask" @change-task="changeTask" />
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { PlusCircleFilled, InfoCircleFilled } from '@ant-design/icons-vue';
import TaskEditModal from './taskEditModal.vue';
import TaskAddModal from './taskListModal.vue';
import { judgeArrResult } from '@/utils';
import { isEmpty, orderBy, groupBy } from 'lodash';
import { nanoid } from 'nanoid';
import { getTaskDefList } from '@/api/pipeline';
import { PipelineOperationTypeCode } from '@/enums/pipelineEnum';
import { message } from 'ant-design-vue';

enum ParamField {
  componentLabel = 'componentLabel',
  pipelineId = 'pipelineId',
  appCode = 'appCode',
}
// parentUuid为'0'代表是首个节点
const firstTaskParentUuid = '0';
const pipelineStore = inject<any>('store');
const route = useRoute();
const isView = computed(() => route.params.type == PipelineOperationTypeCode.info);
console.log('isView', isView.value, route.params.type);
const pipelineData = ref<Pipeline.Task[]>([]);
const computedTasks = computed(() => {
  if (pipelineData.value.length == 0) return [];
  const groupObj = groupBy(pipelineData.value, (item: Pipeline.Task) => item.parentUuid || '');
  const arr = Object.values(groupObj);
  const orderArr = [arr.find((item: any) => item[0].parentUuid == firstTaskParentUuid)];
  let index = 0;
  while (index < arr.length) {
    index++;
    const nextbling = arr.find((item: any) => {
      const previous_task_arr = orderArr[orderArr.length - 1]?.map((i: Pipeline.Task) => i.uuid) || [];
      return judgeArrResult(item[0].parentUuid?.split(',') || [], previous_task_arr);
    });
    if (nextbling) {
      orderArr.push(nextbling);
    }
  }
  return orderArr;
});
const taskEditModalRef = ref();
const taskAddModalRef = ref();
//右侧抽屉挂载的节点
const pipelineConfigRef = ref();
// 是否添加串行任务
const isSerialAdd = ref(false);
// 添加串行任务时，暂存前一个任务节点
const prevTaskList = ref<Pipeline.Task[]>([]);
// 添加并行任务时，暂存前一个任务节点
const prevTask = ref<Pipeline.Task>({} as Pipeline.Task);
// 当前需要更换的任务
const currentChangeTask = ref<Pipeline.Task>({} as Pipeline.Task);
// 任务定义列表
const taskDefList = ref<Pipeline.TaskDefResult[]>([]);
// 是否是切换任务
const isChange = ref(false);

onMounted(async () => {
  const data = await getTaskDefList();
  taskDefList.value = data;
});

watch(
  () => pipelineStore.getFlowChoreographyData,
  (newVal) => {
    pipelineData.value = newVal;
  },
  { immediate: true },
);

const getHiddenParam = (schema: string) => {
  // 非模版没有组件、流水线相关信息，直接返回空对象
  if (!pipelineStore.getBaseInfoData) return {};
  const taskSchema = eval(`(${schema})`);
  const componentIdItem = taskSchema.find((item: any) => item.field == ParamField.componentLabel);
  const pipelineIdItem = taskSchema.find((item: any) => item.field == ParamField.pipelineId);
  const appCode = taskSchema.find((item: any) => item.field == ParamField.appCode);
  const params = {} as any;
  if (componentIdItem) {
    params[ParamField.componentLabel] = pipelineStore.getBaseInfoData.componentLabel;
  }
  if (pipelineIdItem) {
    params[ParamField.pipelineId] = pipelineStore.getBaseInfoData.code;
  }
  if (appCode) {
    params[ParamField.appCode] = pipelineStore.getBaseInfoData.applicationCode;
  }
  return params;
};

const createTask = (data: Pipeline.TaskInfo, prevTaskId: string | null, index = 1): Pipeline.Task => {
  const params = getHiddenParam(data.schema);
  return {
    uuid: nanoid(),
    taskDefUuid: data.taskId,
    name: data.taskName,
    code: data.taskCode,
    sortIndex: index,
    parentUuid: prevTaskId,
    params: JSON.stringify(params),
    schema: data.schema,
    isValidateError: false,
  };
};

const getChangedTask = (data: Pipeline.TaskInfo) => {
  const params = getHiddenParam(data.schema);
  return {
    ...currentChangeTask.value,
    taskDefUuid: data.taskId,
    name: data.taskName,
    code: data.taskCode,
    params: JSON.stringify(params),
    schema: data.schema,
    isValidateError: false,
  };
};

const changeTask = (data: Pipeline.Task) => {
  currentChangeTask.value = data;
  isChange.value = true;
  taskEditModalRef.value.onClose();
  taskAddModalRef.value.showDrawer();
};

// 添加串行任务
const addSerialTask = (prevTasks: Pipeline.Task[], length: number) => {
  if (length === 10) {
    message.warn('串行任务最多添加10个');
    return;
  }
  isSerialAdd.value = true;
  isChange.value = false;
  prevTaskList.value = prevTasks;
  taskAddModalRef.value.showDrawer();
};

// 添加并行任务
const addParallelTask = (task: Pipeline.Task, length: number) => {
  if (length === 10) {
    message.warn('并行任务最多添加10个');
    return;
  }
  isSerialAdd.value = false;
  isChange.value = false;
  prevTask.value = task;
  taskAddModalRef.value.showDrawer();
};

const handleAddTask = (data: Pipeline.TaskInfo) => {
  let currentTask: Pipeline.Task = {} as Pipeline.Task;
  // 判断是否是更换任务
  if (isChange.value) {
    const currentTask = getChangedTask(data);
    pipelineData.value.splice(
      pipelineData.value.findIndex((item: Pipeline.Task) => item.uuid === currentTask.uuid),
      1,
      currentTask,
    );
    taskEditModalRef.value.onOpen(currentTask);
    return;
  }

  // 添加串行任务
  if (isSerialAdd.value) {
    // 当前新增任务的父任务设置为前一个串行任务的id，多个则用逗号连接
    const previous_task_arr = prevTaskList.value?.map((item: Pipeline.Task) => item.uuid) || [];
    currentTask = createTask(data, previous_task_arr.length == 0 ? firstTaskParentUuid : previous_task_arr.join(','));
    // 下一个任务的父任务改为当前任务的id
    pipelineData.value.forEach((item: Pipeline.Task) => {
      if (judgeArrResult(item.parentUuid?.split(',') || [], previous_task_arr)) {
        item.parentUuid = currentTask.uuid;
      }
    });
    pipelineData.value.push(currentTask);
  } else {
    // 添加并行任务
    // 当前任务下标为设置为index + 1
    currentTask = createTask(data, prevTask.value.parentUuid, prevTask.value.sortIndex + 1);
    // 并行的后面几个任务下标在原来的基础上 + 1
    const currentTasks = pipelineData.value.filter(
      (item: Pipeline.Task) => item.parentUuid === prevTask.value.parentUuid,
    );
    pipelineData.value
      .filter((item: Pipeline.Task) => item.parentUuid === prevTask.value.parentUuid)
      .forEach((item: Pipeline.Task) => {
        if (item.sortIndex > prevTask.value.sortIndex) {
          item.sortIndex = item.sortIndex + 2;
        }
      });
    // 下一个串行任务的父任务统一拼上当前任务的id
    pipelineData.value
      .filter((item: Pipeline.Task) =>
        judgeArrResult(
          item.parentUuid?.split(',') || [],
          currentTasks.map((i: Pipeline.Task) => i.uuid),
        ),
      )
      .forEach((item: Pipeline.Task) => {
        item.parentUuid = `${item.parentUuid},${currentTask.uuid}`;
      });
    pipelineData.value.push(currentTask);
  }
  taskEditModalRef.value.onOpen(currentTask);
};

// 删除任务
const deleteSerialTask = (uuid: string) => {
  const currentTask = pipelineData.value.find((item: Pipeline.Task) => item.uuid === uuid);
  // 判断是否有跟该任务有同样父任务的节点，有则是删除并行任务，没有则是删除串行任务
  const isParallelTask =
    pipelineData.value.filter((item: Pipeline.Task) => item.parentUuid === currentTask?.parentUuid)?.length > 1;
  if (isParallelTask) {
    // 删除并行任务，将下一个串行任务的父任务id去掉当前任务的id
    pipelineData.value.forEach((item: Pipeline.Task) => {
      if (item.parentUuid && item.parentUuid?.indexOf(uuid) > -1) {
        const previous_task_arr = item.parentUuid.split(',');
        previous_task_arr.splice(
          previous_task_arr.findIndex((i: string) => i === uuid),
          1,
        );
        item.parentUuid = previous_task_arr.join(',');
      }
    });
  } else {
    // 删除串行任务， 将下一个串行任务的父任务改成当前任务的父任务节点
    pipelineData.value.forEach((item: Pipeline.Task) => {
      if (item.parentUuid === uuid) {
        item.parentUuid = currentTask?.parentUuid || '';
      }
    });
  }
  // 删除当前taskId的任务
  pipelineData.value.splice(
    pipelineData.value.findIndex((item: Pipeline.Task) => item.uuid === uuid),
    1,
  );
};

const openTaskEdit = (item: Pipeline.Task) => {
  const params = getHiddenParam(item.schema);
  if (!isEmpty(params)) {
    item.params = JSON.stringify({ ...JSON.parse(item.params || '{}'), ...params });
  }
  taskEditModalRef.value.onOpen(unref(item));
};
</script>
<style lang="less" scoped>
.pipeline-config-container {
  height: 100%;
  overflow: auto;
  background: #f3f7fb;
  padding: 30px;
  .pipeline-config {
    position: relative;
    display: flex;
    border-radius: 4px;
    .serial-task-add {
      width: 48px;
      text-align: center;
      margin-top: 10px;
      position: relative;
      z-index: 2;
      &::before {
        border-top: 1px solid #dbdbdb;
        content: '';
        position: absolute;
        top: 10px;
        left: 0px;
        width: 48px;
        z-index: -1;
      }
    }
    .add-icon {
      font-size: 16px;
      cursor: pointer;
      color: #989a9c;
    }
    .task-group {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
      z-index: 2;
      &::before {
        border-top: 1px solid #dbdbdb;
        content: '';
        position: absolute;
        top: 20px;
        width: 100%;
        z-index: -1;
      }
      .parallel-wiring {
        height: 40px;
        border-left: 1px solid #dbdbdb;
        position: relative;
        flex-shrink: 0;
      }
    }

    .task-item-container {
      width: 100%;
      display: flex;
      justify-content: center;
      .w-24 {
        width: 24px;
      }
    }
    .linked {
      position: relative;
      &::before {
        position: absolute;
        content: '';
        bottom: 18px;
        height: 60px;
        width: 100%;
        border: 1px solid rgba(225, 230, 237, 1);
        border-top: none;
        border-bottom-right-radius: 8px;
        border-bottom-left-radius: 8px;
        z-index: -1;
      }
    }
    .linked-item {
      position: relative;
      &::before {
        position: absolute;
        content: '';
        bottom: 18px;
        height: 80px;
        width: 100%;
        border: 1px solid rgba(225, 230, 237, 1);
        border-top: none;
        z-index: -1;
      }
    }
    .task-item {
      flex-shrink: 0;
      background-color: #fff;
      border: 1px solid #e9edf0;
      border-radius: 8px;
      min-width: 130px;
      box-shadow: 0 2px 4px 0 rgba(38, 38, 38, 0.1);
      cursor: pointer;
      height: 40px;
      padding: 0 16px;
      transition: all 0.218s ease-in;
      display: flex;
      align-items: center;
      justify-content: center;
      &:hover {
        border: 1px solid rgba(37, 144, 255, 1);
        color: #2590ff;
        .add-icon {
          color: #2590ff;
        }
        .linked {
          border-color: #2590ff;
        }
      }
      .validate-error-icon {
        color: #e6371c;
        margin-left: 4px;
      }
    }
    .validate-error-border {
      border-color: #e6371c;
    }
    .task-item-add {
      background: #f3f7fb;
      border: 1px solid rgba(181, 193, 210, 1);
      box-shadow: 0px 2px 4px 0px rgba(107, 132, 165, 0.15);
      border-radius: 4px;
      margin-top: 20px;
      > span {
        margin-right: 8px;
      }
    }

    .serial-task-add-last {
      position: relative;
      z-index: 2;
      margin: 0 24px;
      &::before {
        border-top: 1px solid #dbdbdb;
        content: '';
        position: absolute;
        top: 19px;
        left: -24px;
        width: 24px;
        z-index: -1;
      }
    }
  }

  :deep(.ant-drawer-open) {
    right: 24px;
    top: 137px;
    height: calc(100vh - 147px);
  }

  :deep(.ant-drawer-title) {
    font-weight: 600;
  }

  :deep(.ant-drawer-right) {
    top: 137px;
  }
}
</style>
